{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "7077e880-d933-4422-aa7f-fa9b3756121c",
   "metadata": {},
   "source": [
    "# ReAct\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9624f5c5-4719-4143-b4d2-a23440133de4",
   "metadata": {},
   "source": [
    "## 1 ReAat using langgraph"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "836eeff8-b5b2-4543-a24a-223231016e0b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[StructuredTool(name='multiply', description='multi first_int and second_int', args_schema=<class 'langchain_core.utils.pydantic.multiply'>, func=<function multiply at 0x00000268C5511A80>), StructuredTool(name='add', description='add first_int and second_int', args_schema=<class 'langchain_core.utils.pydantic.add'>, func=<function add at 0x00000268C5512020>), StructuredTool(name='get_weather', description='Call to get the current weather.', args_schema=<class 'langchain_core.utils.pydantic.get_weather'>, func=<function get_weather at 0x00000268C55125C0>), StructuredTool(name='get_coolest_cities', description='Get a list of coolest cities', args_schema=<class 'langchain_core.utils.pydantic.get_coolest_cities'>, func=<function get_coolest_cities at 0x00000268C5512F20>)]\n"
     ]
    }
   ],
   "source": [
    "from langgraph.prebuilt import ToolNode, tools_condition\n",
    "from langchain_core.tools import tool\n",
    "# 定义函数并应用工具装饰器\n",
    "@tool\n",
    "def multiply(first_int: int, second_int: int) -> int:\n",
    "    \"\"\"multi first_int and second_int\"\"\"\n",
    "    return first_int * second_int\n",
    "\n",
    "@tool\n",
    "def add(first_int: int, second_int: int) -> int:\n",
    "    \"\"\"add first_int and second_int\"\"\"\n",
    "    print(\"\\n add function\")\n",
    "    return first_int + second_int\n",
    "@tool\n",
    "def get_weather(location: str):\n",
    "    \"\"\"Call to get the current weather.\"\"\"\n",
    "    if location.lower() in [\"sf\", \"san francisco\"]:\n",
    "        return \"It's 60 degrees and foggy.\"\n",
    "    else:\n",
    "        return \"It's 90 degrees and sunny.\"\n",
    "\n",
    "\n",
    "@tool\n",
    "def get_coolest_cities():\n",
    "    \"\"\"Get a list of coolest cities\"\"\"\n",
    "    return \"nyc, sf\"\n",
    "tools = [multiply, add, get_weather, get_coolest_cities]\n",
    "print(tools)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "75a49289-8cda-4604-a1c9-8ce6b5ab7f47",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from typing import Literal\n",
    "\n",
    "from langchain_ollama import ChatOllama\n",
    "llm = ChatOllama(base_url=\"http://192.168.99.142:11434\", model=\"hhao/qwen2.5-coder-tools:latest\")\n",
    "\n",
    "from langgraph.graph import StateGraph, MessagesState, START, END\n",
    "from langgraph.prebuilt import ToolNode, tools_condition\n",
    "\n",
    "model_with_tools = llm.bind_tools(tools)\n",
    "\n",
    "tool_node = ToolNode(tools)\n",
    "\n",
    "def should_continue(state: MessagesState):\n",
    "    messages = state[\"messages\"]\n",
    "    last_message = messages[-1]\n",
    "    if last_message.tool_calls:\n",
    "        return \"tools\"\n",
    "    return END\n",
    "\n",
    "\n",
    "def call_model(state: MessagesState):\n",
    "    messages = state[\"messages\"]\n",
    "    response = model_with_tools.invoke(messages)\n",
    "    return {\"messages\": [response]}\n",
    "\n",
    "\n",
    "workflow = StateGraph(MessagesState)\n",
    "\n",
    "# Define the two nodes we will cycle between\n",
    "workflow.add_node(\"agent\", call_model)\n",
    "workflow.add_node(\"tools\", tool_node)\n",
    "\n",
    "workflow.add_edge(START, \"agent\")\n",
    "workflow.add_conditional_edges(\"agent\", should_continue, [\"tools\", END])\n",
    "workflow.add_edge(\"tools\", \"agent\")\n",
    "\n",
    "app = workflow.compile()\n",
    "from IPython.display import Image, display\n",
    "\n",
    "try:\n",
    "    display(Image(app.get_graph().draw_mermaid_png()))\n",
    "except Exception:\n",
    "    # This requires some extra dependencies and is optional\n",
    "    pass"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "fc83aed1-f210-49b9-ac1c-c71da7052079",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "================================\u001b[1m Human Message \u001b[0m=================================\n",
      "\n",
      "what's the weather in sf?\n",
      "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
      "Tool Calls:\n",
      "  get_weather (3c67d7ad-bec6-48a2-a27b-9bf336a4e93a)\n",
      " Call ID: 3c67d7ad-bec6-48a2-a27b-9bf336a4e93a\n",
      "  Args:\n",
      "    location: San Francisco\n",
      "=================================\u001b[1m Tool Message \u001b[0m=================================\n",
      "Name: get_weather\n",
      "\n",
      "It's 60 degrees and foggy.\n",
      "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
      "\n",
      "The current weather in San Francisco is 60 degrees with fog. Is there anything else you'd like to know or discuss about this information?\n"
     ]
    }
   ],
   "source": [
    "# example with a single tool call\n",
    "for chunk in app.stream(\n",
    "    {\"messages\": [(\"human\", \"what's the weather in sf?\")]}, stream_mode=\"values\"\n",
    "):\n",
    "    chunk[\"messages\"][-1].pretty_print()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "2753fd52-10d1-4ea7-9c57-f34c585d2b42",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "================================\u001b[1m Human Message \u001b[0m=================================\n",
      "\n",
      "what's the weather in the coolest cities?\n",
      "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
      "Tool Calls:\n",
      "  get_coolest_cities (6db69d15-5e80-4b3d-8b2e-27ef6640cf7a)\n",
      " Call ID: 6db69d15-5e80-4b3d-8b2e-27ef6640cf7a\n",
      "  Args:\n",
      "=================================\u001b[1m Tool Message \u001b[0m=================================\n",
      "Name: get_coolest_cities\n",
      "\n",
      "nyc, sf\n",
      "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
      "Tool Calls:\n",
      "  get_weather (5a7439ab-cd25-456e-b6a7-e1a9576fd899)\n",
      " Call ID: 5a7439ab-cd25-456e-b6a7-e1a9576fd899\n",
      "  Args:\n",
      "    location: nyc\n",
      "=================================\u001b[1m Tool Message \u001b[0m=================================\n",
      "Name: get_weather\n",
      "\n",
      "It's 90 degrees and sunny.\n",
      "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
      "Tool Calls:\n",
      "  get_weather (aaff8790-0cf0-4d94-b8d1-8d189b145e26)\n",
      " Call ID: aaff8790-0cf0-4d94-b8d1-8d189b145e26\n",
      "  Args:\n",
      "    location: sf\n",
      "=================================\u001b[1m Tool Message \u001b[0m=================================\n",
      "Name: get_weather\n",
      "\n",
      "It's 60 degrees and foggy.\n",
      "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
      "\n",
      "The weather in the coolest cities is as follows:\n",
      "- New York City: It's 90 degrees and sunny.\n",
      "- San Francisco: It's 60 degrees and foggy.\n"
     ]
    }
   ],
   "source": [
    "# example with a multiple tool calls in succession\n",
    "\n",
    "for chunk in app.stream(\n",
    "    {\"messages\": [(\"human\", \"what's the weather in the coolest cities?\")]},\n",
    "    stream_mode=\"values\",\n",
    "):\n",
    "    chunk[\"messages\"][-1].pretty_print()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "408d5516-a15d-43bc-aea7-e4725e80f35f",
   "metadata": {},
   "source": [
    "## 2 pre-built ReAct agent"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "dcc6d3ea-f794-4b94-9870-337538bc8481",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from langgraph.prebuilt import create_react_agent\n",
    "from langchain_ollama import ChatOllama\n",
    "model = ChatOllama(base_url=\"http://192.168.99.142:11434\", model=\"hhao/qwen2.5-coder-tools:latest\")\n",
    "graph = create_react_agent(model, tools=tools)\n",
    "\n",
    "from IPython.display import Image, display\n",
    "display(Image(graph.get_graph().draw_mermaid_png()))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "7b413af9-4de5-4792-a457-3633b7e0a387",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "================================\u001b[1m Human Message \u001b[0m=================================\n",
      "\n",
      "what's the weather in the coolest cities?\n",
      "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
      "Tool Calls:\n",
      "  get_coolest_cities (c2283d98-1537-4173-b898-53f6c771bf51)\n",
      " Call ID: c2283d98-1537-4173-b898-53f6c771bf51\n",
      "  Args:\n",
      "=================================\u001b[1m Tool Message \u001b[0m=================================\n",
      "Name: get_coolest_cities\n",
      "\n",
      "nyc, sf\n",
      "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
      "Tool Calls:\n",
      "  get_weather (0f11a36d-a320-41e2-aada-cfe9abcf8dda)\n",
      " Call ID: 0f11a36d-a320-41e2-aada-cfe9abcf8dda\n",
      "  Args:\n",
      "    location: nyc\n",
      "=================================\u001b[1m Tool Message \u001b[0m=================================\n",
      "Name: get_weather\n",
      "\n",
      "It's 90 degrees and sunny.\n",
      "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
      "Tool Calls:\n",
      "  get_weather (4e990e23-264b-429f-a613-9ffa8b8d141e)\n",
      " Call ID: 4e990e23-264b-429f-a613-9ffa8b8d141e\n",
      "  Args:\n",
      "    location: sf\n",
      "=================================\u001b[1m Tool Message \u001b[0m=================================\n",
      "Name: get_weather\n",
      "\n",
      "It's 60 degrees and foggy.\n",
      "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
      "\n",
      "The weather in the coolest cities, New York City (NYC) and San Francisco (SF), is as follows:\n",
      "\n",
      "- **New York City (NYC):** It's 90 degrees and sunny.\n",
      "- **San Francisco (SF):** It's 60 degrees and foggy.\n",
      "\n",
      "If you need more information or have any other questions, feel free to ask!\n"
     ]
    }
   ],
   "source": [
    "# example with a multiple tool calls in succession\n",
    "\n",
    "for chunk in graph.stream(\n",
    "    {\"messages\": [(\"human\", \"what's the weather in the coolest cities?\")]},\n",
    "    stream_mode=\"values\",\n",
    "):\n",
    "    chunk[\"messages\"][-1].pretty_print()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d9a89153-db96-438c-ab9a-11f5dfc71535",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
